<?php

use Cola\Response;

/**
 * 服务端接口
 * @param $url
 * @param $command
 * @param $params
 * @return mixed
 * @throws Exception
 */
function serverApi($url, $command, $params = '')
{
    $res = curl($url. '/' .$command. '?' . $params);
    return $res;
}

function feishuNotify($url, $massage)
{
    $res = curl(
        $url,
        json_encode(['msg_type'=>'text','content'=>['text'=>$massage]]),
        1,
        ["Content-Type: application/json"]
    );
    $res = json_decode($res,true);
    if ($res['code'] === 11232) {
        $res = curl(
            $url,
            json_encode(['msg_type'=>'text','content'=>['text'=>$massage]]),
            1,
            ["Content-Type: application/json"]
        );
    }
}

function htmlToBBCode($html)
{
    // 将HTML实体解码
    $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');

    // 使用正则表达式或DOM解析器来处理HTML
    // 这里我们使用简单的正则表达式来处理（注意：这可能不是最健壮的方法）

    // 处理段落
    $html = str_replace(["<p><br></p>"], "<br/>", $html);
    $html = preg_replace('/<p\s*[\/]?>/i', '', $html);
    $html = preg_replace('/<\/?p\s*[\/]?>/i', '<br/>', $html);

    // 处理颜色（这里仅处理内联样式）
    $html = preg_replace_callback('/<span\s+style="color:\s*rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+)\s*\)\s*;">(.*?)<\/span>/i', function ($matches) {
        $hexColor = handleHtmlColor($matches);

        // 假设BBCode有一个[color]标签，但实际上BBCode可能不使用十六进制颜色
        // 这里我们仅返回颜色代码和文本，不添加BBCode的[color]标签
        // 如果你想添加，可以返回 '[color='.$hexColor.']'.$matches[4].'[/color]'
        return '<color=' . $hexColor . '>' . $matches[4] . '</color>'; // 注意：这可能需要你自定义BBCode解析器来支持
        // 或者，如果你不确定BBCode是否支持颜色，可以省略颜色并仅返回文本
        return $matches[4];
    }, $html);

    // 处理颜色（这里仅处理内联样式）
    $html = preg_replace_callback('/<strong\s+style="color:\s*rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+)\s*\)\s*;">(.*?)<\/strong>/i', function ($matches) {
        $hexColor = handleHtmlColor($matches);
        // 假设BBCode有一个[color]标签，但实际上BBCode可能不使用十六进制颜色
        // 这里我们仅返回颜色代码和文本，不添加BBCode的[color]标签
        // 如果你想添加，可以返回 '[color='.$hexColor.']'.$matches[4].'[/color]'
        return '<b><color=' . $hexColor . '>' . $matches[4] . '</color></b>'; // 注意：这可能需要你自定义BBCode解析器来支持
        // 或者，如果你不确定BBCode是否支持颜色，可以省略颜色并仅返回文本
        return $matches[4];
    }, $html);

    // 处理粗体
    $html = str_replace('<strong>', '<b>', $html);
    $html = str_replace('</strong>', '</b>', $html);

    $html = str_replace(["\n", "\n"], "<br/>", $html);
    $html = str_replace(["<br>", "</br>"], "<br/>", $html);

    // 处理连续的换行符作为空一行
    $html = preg_replace("/\[br\]\s*\[br\]+/", "<br/><br/>", $html);

    return $html;
}

function handleHtmlColor($matches)
{
    // 将 RGB 颜色转换为十六进制
    $red = dechex($matches[1]);
    $green = dechex($matches[2]);
    $blue = dechex($matches[3]);

    // 确保十六进制颜色码是两位数的（例如，将 'a' 转换为 '0a'）
    $red = strlen($red) < 2 ? '0' . $red : $red;
    $green = strlen($green) < 2 ? '0' . $green : $green;
    $blue = strlen($blue) < 2 ? '0' . $blue : $blue;

    $hexColor = '#' . $red . $green . $blue;

    return $hexColor;
}

/**
 * 输出并终止，用于调试变量
 *
 * @param mixed $var 要输出的变量
 * @param bool $exit 是否要终止
 * @param bool $print 使用print_r函数（值为true时） 或者 var_dump函数（值为false时）
 * @return void
 */
function halt($var, $exit = true, $print = true)
{
    echo '<pre>';
    $print ? print_r($var) : var_dump($var);
    echo '</pre>';
    $exit && exit();
}

function dd($var)
{
    halt($var);
}

/**
 * 多维数组合并（支持多数组）
 *
 * @return array
 */
function array_merge_multi()
{
    $args = func_get_args();
    $array = [];
    foreach ( $args as $arg )
    {
        if ( is_array($arg) )
        {
            foreach ( $arg as $k => $v )
            {
                if ( is_array($v) )
                {
                    $array[$k] = isset($array[$k]) ? $array[$k] : [];
                    $array[$k] = array_merge_multi($array[$k], $v);
                } else {
                    $array[$k] = $v;
                }
            }
        }
    }
    return $array;
}

/**
 * 写日志文件
 *
 * @param string $filename 日志文件名
 * @param string $loginfo 日志内容
 * @param bool $echo 是否输出日志信息
 * @param bool $exit 是否中止程序
 *
 */
function logfile($filename, $loginfo, $echo = false, $exit = false)
{
    is_array($loginfo) && $loginfo = var_export($loginfo, true);
    $loginfo = '[' . date ('H:i:s') . '] ' . $loginfo;

    \Cola\Ext\Log\Factory::setChannel($filename);
    \Cola\Ext\Log\Factory::info($loginfo);

    // 调试模式下输出错误内容
    if($echo)
    {
        echo $loginfo;
    }

    $exit && exit;
}

/**
 * script 输出信息
 * @param $message
 */
function scriptOut($message){
    exit("<head> <meta http-equiv='Content-Type' content='text/html'; charset='utf-8'> <script>alert('$message')</script></head>");
}

/**
 *
 * 由于mkdir的mode参数会受系统的umask值影响而导致不能赋予777权限，所以这里手动再调用一次chmod来改变目录权限
 *
 * @param string   $path
 * @param int      $mode
 * @param bool     $recursive
 *
 * @return bool
 */
function mkchdir($path, $mode, $recursive = false)
{
    $ret = mkdir($path, $mode, $recursive);
    $ret &= chmod($path, $mode);

    return boolval($ret);
}

// 得到当前用户Ip地址
function ip()
{
    $pattern = '/(\d{1,3}\.){3}\d{1,3}/';
    if (isset ( $_SERVER ['HTTP_X_FORWARDED_FOR'] ) && preg_match_all ( $pattern, $_SERVER ['HTTP_X_FORWARDED_FOR'], $mat )) {
        foreach ( $mat [0] as $ip ) {
            //得到第一个非内网的IP地址
            if ((false === strpos ( $ip, '192.168.' )) && (false === strpos ( $ip, '10.' )) && (false === strpos ( $ip, '172.16.' ))) {
                return $ip;
            }
        }
        return $ip;
    } else {
        if (isset ( $_SERVER ['HTTP_CLIENT_IP'] ) && preg_match ( $pattern, $_SERVER ['HTTP_CLIENT_IP'] )) {
            return $_SERVER ['HTTP_CLIENT_IP'];
        } else {
            return $_SERVER ['REMOTE_ADDR'];
        }
    }
}

// 得到无符号整数表示的ip地址
function int_ip()
{
    return sprintf ( '%u', ip2long ( ip() ) );
}

// 文本入库前的过滤工作
function safe_text($text, $htmlspecialchars = true)
{
    $text = trim ( strip_tags ( $text ) );
    return $htmlspecialchars ? htmlspecialchars ( $text ) : $text;
}

/**
 * curl操作封装
 *
 * @param string $url 要访问的网址，get方法的时候请在此网址上直接带上参数
 * @param string/array $params 要post的数据，如果是array，方法内部会转成string
 * @param int/bool $return 1代表返回 0代表直接输出
 * @param array  $header 请求头
 * @param array  $cookie 模拟cookie 格式须为关联数组， key 为 jar 时代表请求cookie, key 为 file 时代表发送cookie； value代表完整的cookie路径和文件，该文件可以通过 tempnam(string $dir , 'cookie') 获得
 * @param array  $option 其它的选项，可参考http://php.net/manual/en/weixin_function.curl-getinfo.php
 * @return mixed 响应内容（如果需要获得响应头信息，可以在调用此函数后直接访问 全局变量 $_EVN['CURL_HEADER']）
 * @throws Exception
 */
function curl($url, $params ='', $return = 1, $header = array(), $cookie = array(), $option = array())
{
    $ch = curl_init($url); // 初始化curl并设置链接
    // curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
    // 设置是否为post传递
    curl_setopt($ch, CURLOPT_POST, (bool)$params);
    // 对于https 设定为不验证证书和host
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, $return);//设置是否返回信息

    if($cookie){
        $key = array_keys($cookie);
        curl_setopt($ch, $key[0]=='jar' ? CURLOPT_COOKIEJAR : CURLOPT_COOKIEFILE, $cookie['file']);
    }
    if($params){
        if(is_array($params)){
            $params = http_build_query($params);
        }
        // POST 数据
        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    }
    if($header){
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //设置头信息的地方
    }else{
        PHP_SAPI != 'cli' && isset($_SERVER['HTTP_USER_AGENT']) && curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
    }
    foreach($option as $key => $val){
        curl_setopt($ch, $key, $val);
    }
    $response = curl_exec($ch); // 执行并接收返回信息
    if(curl_errno($ch)){
        // 出错则显示错误信息
        $message = curl_error($ch);
        throw new Exception($message);
    }
    if(! empty($option[CURLOPT_HEADER])){
        // 获得响应结果里的：头大小
        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        // 根据头大小去获取头信息内容
        $_EVN['CURL_HEADER'] = substr($response, 0, $header_size);
        $response = substr($response, $header_size);
    }

    curl_close($ch); // 关闭curl链接
    return $response;
}

// 根据玩家账号获取分表
function calc_hash_tbl($u, $n = 256)
{
    $h 	= sprintf('%u', crc32($u));
    $h1 = intval($h / $n);
    return $h1 % $n;
}

/**
 * 比较前后俩个时间戳 默认是5分钟 (300)
 * @param int|string $sttime 开始时间
 * @param int $mi 分钟默认是5分钟
 * @param int $endtime 结束时间
 * @return bool
 */
function is_timeout($sttime, $mi = 5, $endtime)
{
    return abs(($endtime ? : $_SERVER['REQUEST_TIME']) - (int)($sttime)) > $mi * 60;
}

/**
 * 生成随机数/字符串
 * @param int $length           长度
 * @param boolean $numeric      是否为数字 false=字符串 true=数字
 */
function random($length, $numeric = false) {
    mt_srand ( ( double ) microtime () * 1000000 );
    if (( boolean ) $numeric) {
        $hash = sprintf ( '%0' . $length . 'd', mt_rand ( 0, pow ( 10, $length ) - 1 ) );
    } else {
        $hash = '';
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
        $max = strlen ( $chars ) - 1;
        for($i = 0; $i < $length; $i ++) {
            $hash .= $chars [mt_rand ( 0, $max )];
        }
    }
    return $hash;
}

/*
* 截取字符串
* @param $string 要截取的字符串
* @param $length 截取长度
* @param $dot
* @return 取得到的结果集
*/
function cutstr($string, $length, $dot = ' ...', $charset = 'utf-8') {
    if (strlen ( $string ) <= $length) {
        return $string;
    }
    $string = str_replace ( array ('&amp;', '&quot;', '&lt;', '&gt;' ), array ('&', '"', '<', '>' ), $string );
    $strcut = '';
    if (strtolower ( $charset ) == 'utf-8') {
        $n = $tn = $noc = 0;
        while ( $n < strlen ( $string ) ) {

            $t = ord ( $string [$n] );
            if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                $tn = 1;
                $n ++;
                $noc ++;
            } elseif (194 <= $t && $t <= 223) {
                $tn = 2;
                $n += 2;
                $noc += 2;
            } elseif (224 <= $t && $t < 239) {
                $tn = 3;
                $n += 3;
                $noc += 2;
            } elseif (240 <= $t && $t <= 247) {
                $tn = 4;
                $n += 4;
                $noc += 2;
            } elseif (248 <= $t && $t <= 251) {
                $tn = 5;
                $n += 5;
                $noc += 2;
            } elseif ($t == 252 || $t == 253) {
                $tn = 6;
                $n += 6;
                $noc += 2;
            } else {
                $n ++;
            }
            if ($noc >= $length) {
                break;
            }
        }
        if ($noc > $length) {
            $n -= $tn;
        }
        $strcut = substr ( $string, 0, $n );
    } else {
        for($i = 0; $i < $length - 3; $i ++) {
            $strcut .= ord ( $string [$i] ) > 127 ? $string [$i] . $string [++ $i] : $string [$i];
        }
    }
    $strcut = str_replace ( array ('&', '"', '<', '>' ), array ('&amp;', '&quot;', '&lt;', '&gt;' ), $strcut );
    return $strcut . $dot;
}
/**
 * 获取和设置配置参数
 * @param string|array  $name 参数名
 * @param mixed         $value 参数值
 * @return mixed
 */
function config($name = '', $value = null)
{
    static $config = array();
    // 读取整个配置数组
    if($name === ''){
        return $config;
    }
    // 读取指定配置
    elseif (is_string($name)){
        return $config[$name];
    }
    // 写入配置
    else{
        $config[$name] = $value;
    }
}

function cache($name, $value = '', $options = array('expire' => 0, 'path' => 'cache/'))
{
    // 缓存文件
    $file = $options['path'] . '.ht-' . $name;
    // 获取缓存
    if ('' === $value) {
        // 如果没有此缓存文件
        if(! is_file($file)){
            return null;
        }
        $con = file_get_contents($file);
        $con = explode('^', $con, 3);
        if ($con[1]>0 && time() > filemtime($file) + $con[1]){
            // 缓存过期删除缓存文件
            unlink($file);
            return null;
        }
        return $con[0] ? json_decode($con[2]) : $con[2];
    }
    // 删除缓存
    elseif (is_null($value)) {
        @ unlink($file);
        return true;
    }
    // 写入缓存
    else {
        // 缓存的有效期
        if (is_array($options)){
            $expire = isset($options['expire']) ? $options['expire'] : 0; //修复查询缓存无法设置过期时间
        } else {
            $expire = is_numeric($options) ? $options : 0; //默认快捷缓存设置过期时间
        }
        // 如果要缓存的数据为数组，则先转为字符串
        if(is_array($value))  {
            $value = "1^$expire^" . json_encode($value);
        } else {
            $value = "0^$expire^$value";
        }
        file_put_contents($file, $value);
    }
}

function is_ssl()
{
    if (isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))) {
        return true;
    } elseif (isset($_SERVER['REQUEST_SCHEME']) && 'https' == $_SERVER['REQUEST_SCHEME']) {
        return true;
    } elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
        return true;
    } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) {
        return true;
    }
    return false;
}

function error($message){
    $Response = new Response();
    $Response->json(0,$message);
}

function realCID(){
    return $GLOBALS['CID'] ?? CID;
}
function realGAME_ID(){
    return $GLOBALS['GAME_ID'] ?? GAME_ID;
}
function realPF(){
    return $GLOBALS['PFORM_NAME'] ?? PFORM_NAME;
}

function write($print=true,$exit=true)
{
    $log = [];
    $trace = debug_backtrace();
    foreach ($trace as $frame) {
        if(!isset($frame['file'])) continue;
        $log[] = $frame['file'].'->'.$frame['function'].'::'.$frame['line'];
    };
    halt($log, $exit, $print);

}

